
#include "print.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <chrono>
#include "chartool.h"

chainsaw::SafeLogger &chainsaw::SafeLogger::instance()
{
    static SafeLogger inst;
    return inst;
}

void chainsaw::SafeLogger::setLogFile(std::string const &filename)
{
    std::lock_guard<std::mutex> lock(m_mutex);

    if (m_log_file.is_open())
        return;
    m_log_file.open(filename, std::ios::out | std::ios::app);
    if (!m_log_file.is_open())
    {
        error("Failed to open log file: ");
        exit(0);
    }
}

void chainsaw::SafeLogger::printTime(bool enable)
{
    std::lock_guard<std::mutex> lock(m_mutex);
    m_flags.print_time = enable;
}

void chainsaw::SafeLogger::printIdMessage(bool enable)
{
    std::lock_guard<std::mutex> lock(m_mutex);
    m_flags.print_id_msg = enable;
}

void chainsaw::SafeLogger::printChainLabel(bool enable)
{
    std::lock_guard<std::mutex> lock(m_mutex);
    m_flags.print_chain = enable;
}

template <>
void chainsaw::SafeLogger::log_message(std::string const &s)
{
    judge_headtype(s);
    if (s.empty())
    {
        info("<>");
    }
    else
    {
        if (s.front() == ' ' || s.back() == ' ')
        {
            info('[', s, ']');
        }
        else
        {
            info(s);
        }
    }
    reset_headtype();
}

template <>
void chainsaw::SafeLogger::log_obj(std::string const &s)
{
    if (s.empty())
        log_raw("<>");
    else
    {
        if (s.front() == ' ' || s.back() == ' ')
        {
            log_raw('[', s, ']');
        }
        else
        {
            log_raw(s);
        }
    }
}

template <>
void chainsaw::SafeLogger::log_obj(bool const &b)
{
    std::string data = b ? "True" : "False";
    log_raw(data);
}

template <>
void chainsaw::SafeLogger::log_obj(char const &c)
{
    if (is_print(c))
    {
        log_raw('<', c, '>');
    }
    else
    {
        log_raw(static_cast<int>(c));
    }
}

chainsaw::SafeLogger::~SafeLogger()
{
    if (m_log_file.is_open())
        m_log_file.close();
}

std::string chainsaw::SafeLogger::getTimeStamp() const
{
    auto now = std::chrono::system_clock::now();
    auto itt = std::chrono::system_clock::to_time_t(now);
    std::tm tm{};
#ifdef _WIN32
    localtime_s(&tm, &itt);
#else
    localtime_r(&itt, &tm);
#endif
    std::ostringstream oss;
    oss << std::put_time(&tm, "%m-%d %H:%M:%S");
    return oss.str();
}

std::string chainsaw::SafeLogger::levelToColorString(LogLevel level) const
{
    switch (level)
    {
    case LogLevel::INFO:
        return "\033[32mINFO"; // 绿色
    case LogLevel::WARN:
        return "\033[33mWARN"; // 黄色
    case LogLevel::ERROR:
        return "\033[31mERR "; // 红色
    default:
        return "UNKNOWN";
    }
}

std::string chainsaw::SafeLogger::stripAnsiCodes(const std::string &s) const
{
    std::string result;
    bool inEscape = false;
    for (char c : s)
    {
        if (c == '\033')
        {
            inEscape = true;
            continue;
        }
        if (inEscape)
        {
            if (c == 'm')
            {
                inEscape = false;
            }
            continue;
        }
        result += c;
    }
    return result;
}

void chainsaw::SafeLogger::judge_headtype(std::string value)
{
    std::lock_guard<std::mutex> lock(m_mutex);
    if (value == "hi" || value == "HI" || value == "hello" || value == "HELLO" || value == "hey" || value == "HEY")
    {
        m_log_separator[0] = '(';
        m_log_separator[1] = '=';
    }
    else if (value == "ih" || value == "IH" || value == "bye" || value == "BYE")
    {
        m_log_separator[0] = '=';
        m_log_separator[1] = ')';
    }
}

void chainsaw::SafeLogger::reset_headtype()
{
    std::lock_guard<std::mutex> lock(m_mutex);
    m_log_separator[0] = '-';
    m_log_separator[1] = '-';
}
